package com.zzyl.nursing.service.impl;

import java.util.*;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.core.domain.AjaxResult;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.framework.config.properties.AliIoTConfigProperties;
import com.zzyl.nursing.dto.DeviceDto;
import com.zzyl.nursing.vo.DeviceVo;
import com.zzyl.nursing.vo.ProductVo;
import org.aspectj.weaver.loadtime.Aj;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.querydsl.QPageRequest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.service.IDeviceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

/**
 * 设备Service业务层处理
 * 
 * @author alexis
 * @date 2025-01-10
 */
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService
{
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private AliIoTConfigProperties aliIoTConfigProperties;
    @Autowired
    private Client client;
    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    /**
     * 查询设备
     * 
     * @param id 设备主键
     * @return 设备
     */
    @Override
    public Device selectDeviceById(Long id)
    {
        return deviceMapper.selectById(id);
    }

    /**
     * 查询设备列表
     * 
     * @param device 设备
     * @return 设备
     */
    @Override
    public List<Device> selectDeviceList(Device device)
    {
        return deviceMapper.selectDeviceList(device);
    }

    /**
     * 新增设备
     * 
     * @param device 设备
     * @return 结果
     */
    @Override
    public int insertDevice(Device device)
    {
        return deviceMapper.insert(device);
    }

    /**
     * 修改设备
     * 
     * @param device 设备
     * @return 结果
     */
    @Override
    public int updateDevice(Device device)
    {
        int result = deviceMapper.updateById(device);
        BatchUpdateDeviceNicknameRequest request=new BatchUpdateDeviceNicknameRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        List<BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo> nicknameInfos=new ArrayList<>();

        BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo nicknameInfo=new BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo();
        nicknameInfo.setDeviceName(device.getDeviceName());
        nicknameInfo.setProductKey(device.getProductKey());
        nicknameInfo.setDeviceName(device.getDeviceName());

        nicknameInfos.add(nicknameInfo);

        request.setDeviceNicknameInfo(nicknameInfos);

        BatchUpdateDeviceNicknameResponse response;
        try {
            response=client.batchUpdateDeviceNickname(request);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if(!response.getBody().getSuccess()){
            throw new BaseException("更新设备失败");
        }

        return result;
    }

    /**
     * 批量删除设备
     * 
     * @param ids 需要删除的设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceByIds(Long[] ids)
    {
        return deviceMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除设备信息
     * 
     * @param id 设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceById(Long id)
    {
        return deviceMapper.deleteById(id);
    }

    /**
     * 从物联网平台同步产品列表
     */
    @Override
    public void syncProductList() {
        //请求参数
        QueryProductListRequest request=new QueryProductListRequest();
        request.setPageSize(200);
        request.setCurrentPage(1);
        //设置实例ID
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());

        //调用第三方查询产品列表
        QueryProductListResponse response;
        try {
            response = client.queryProductList(request);
        } catch (Exception e) {
            throw new BaseException("");
        }
        //判断，如果数据为空，则中断请求
        if(!response.getBody().success){
            throw new BaseException("");
        }
        //存储到redis中
        redisTemplate.opsForValue().set(CacheConstants.IOT_PRODUCT_LIST_ALL, JSONUtil.toJsonStr(response.getBody().getData().getList().getProductInfo()));
    }

    /**
     * 查询所有产品列表
     *
     * @return 产品列表
     */
    @Override
    public List<ProductVo> allProduct() {
        //从redis中获取数据
        String jsonStr = redisTemplate.opsForValue().get(CacheConstants.IOT_PRODUCT_LIST_ALL);
        //如果为空，返回空集合
        if(ObjectUtil.isEmpty(jsonStr)){
            //Collections是一个工具类，里面封装了很多方法，其中包含一个返回空集合的方法
            //emptyList()是返回一个空的集合
            return Collections.emptyList();
        }
        //解析返回
        return JSONUtil.toList(jsonStr,ProductVo.class);
    }

    /**
     * 注册设备
     *
     * @param deviceDto 设备信息
     */

    public void registerDevice1(DeviceDto deviceDto) {

        //判断设备名称是否重复
        String deviceName = deviceDto.getDeviceName();
        Long count = deviceMapper.selectCount(Wrappers.lambdaQuery(Device.class).eq(Device::getDeviceName, deviceName));
        if (Math.toIntExact(count) > 0) {
            throw new BaseException("设备名称已存在，请重新输入");
        }
        //新增Iot设备，IOT和数据库中
        RegisterDeviceRequest request = deviceDto.getRegisterDeviceRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());

        RegisterDeviceResponse response;
        try {
            response = client.registerDevice(request);
        } catch (Exception e) {
            throw new BaseException("IOT注册设备失败");
        }
        //根据状态码判断设备是否保存成功
        if (!response.getBody().getSuccess()) {
            throw new BaseException("IOT注册产品失败");
        }
        //复制设备信息
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        device.setDeviceName(response.getBody().getData().getDeviceName());
        //判断位置类型，是否为0 Integer 0~127
        if (deviceDto.getLocationType().equals(0)) {
            //设置设备物理位置，-1为老人
            device.setPhysicalLocationType(-1);
        }
        //补全返回的IotId
        device.setIotId(response.getBody().getData().getIotId());
        //保存设备到数据库
        try {
            int insert = deviceMapper.insert(device);
            if (insert == 0) {
                deleteIotDevice(device);
            }
        } catch (Exception e) {
            //如果保存失败，删除IOT中设备
            deleteIotDevice(device);
            throw new BaseException("该老人/位置已绑定产品，请重新选择");
        }
    }

    /**
     * 注册设备
     *
     * @param deviceDto
     */
    @Override
    public void registerDevice(DeviceDto deviceDto) {

        //判断设备名称是否重复
        Long count = deviceMapper.selectCount(Wrappers.<Device>lambdaQuery().eq(Device::getDeviceName, deviceDto.getDeviceName()));
        //重复，结束
        if(count!=0){
            throw new BaseException("该设备名称重复，不能新增。");
        }
        //没有重复，注册设备到IOT平台
        // 设置注册设备参数
        // deviceDto.getRegisterDeviceRequest()是注册设备参数
        RegisterDeviceRequest request = deviceDto.getRegisterDeviceRequest();
        //设置实例ID
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        RegisterDeviceResponse response;
        try {
            response= client.registerDevice(request);
        } catch (Exception e) {
            throw new BaseException("注册失败。");
        }
        if(!response.getBody().getSuccess()){
            throw new BaseException("IOT注册产品失败");
        }
        //查询产品，并设置产品名称到设备对象
        QueryProductRequest queryProductRequest=new QueryProductRequest();
        queryProductRequest.setProductKey(deviceDto.getProductKey());
        queryProductRequest.setIotInstanceId(deviceDto.getIotId());
        QueryProductResponse queryProductResponse;
        try {
            queryProductResponse=client.queryProduct(queryProductRequest);
        } catch (Exception e) {
            throw new BaseException("查询产品失败。");
        }
        if(queryProductResponse.getBody().success){
            throw new BaseException("查询产品失败。");
        }

        Device device = BeanUtil.toBean(deviceDto, Device.class);
        device.setProductName(response.getBody().getData().getDeviceName());
        //判断位置是否是0
        //是，设置物理位置-1，并补全新增返回的iotid，保存到数据库
        if(device.getLocationType()==0){
            device.setPhysicalLocationType(-1);
        }

        //否，保存到数据库
        //判断是否保存成功
        //是结束
        device.setIotId(response.getBody().getData().getIotId());
        //否，删除物理网设备数据
        try {
            deviceMapper.insertDevice(device);
        } catch (Exception e) {
            DeleteDeviceRequest deleteDeviceRequest= new DeleteDeviceRequest();
            deleteDeviceRequest.setDeviceName(deviceDto.getDeviceName());
            deleteDeviceRequest.setProductKey(deviceDto.getProductKey());
            deleteDeviceRequest.setIotId(deviceDto.getIotId());
            deleteDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
            try {
                client.deleteDevice(deleteDeviceRequest);
            } catch (Exception ex) {
                throw new BaseException("该老人位置已绑定该产品，绑定失败。");
            }
            throw new BaseException("该老人位置已绑定该产品，绑定失败。");
        }
    }

    /**
     * 删除在IOT的设备
     *
     * @param device 设备信息
     */
    private void deleteIotDevice(Device device) {
        DeleteDeviceRequest deleteRequest = new DeleteDeviceRequest()
                .setDeviceName(device.getDeviceName())
                .setIotId(device.getIotId())
                .setIotInstanceId(aliIoTConfigProperties.getIotInstanceId())
                .setProductKey(device.getProductKey());
        try {
            client.deleteDevice(deleteRequest);
        } catch (Exception ex) {
            throw new BaseException("IOT删除设备失败");
        }
    }

    /**
     * 查询设备详情
     *
     * @param deviceDto
     * @return
     */
    @Override
    public DeviceVo queryDeviceDetail(DeviceDto deviceDto) {
        //查询iot平台中的设备数据
        QueryDeviceDetailRequest queryDeviceDetailRequest=new QueryDeviceDetailRequest();
        queryDeviceDetailRequest.setIotId(deviceDto.getIotId());
        queryDeviceDetailRequest.setProductKey(deviceDto.getProductKey());
        queryDeviceDetailRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDeviceDetailResponse response;
        try {
            response=client.queryDeviceDetail(queryDeviceDetailRequest);
        } catch (Exception e) {
            throw new BaseException("");
        }
        //校验是否成功
        if(!response.getBody().success){
            throw new BaseException("");
        }
        //获取出结果中的设备信息并将结果拷贝到设备详情对象中
        DeviceVo deviceVo=BeanUtil.toBean(response.body.getData(), DeviceVo.class);
        //查询表中数据
        Device device = getOne(Wrappers.lambdaQuery(Device.class).eq(Device::getIotId, deviceDto.getIotId()));
        //合并两部分信息并返回
//        QueryDeviceDetailResponseBody.QueryDeviceDetailResponseBodyData data=response.getBody().getData();
//        BeanUtil.copyProperties(data,deviceVo, CopyOptions.create().ignoreCase());
        BeanUtil.copyProperties(device,deviceVo);
        return deviceVo;
    }

    /**
     * 查看指定产品的已发布物模型中的功能定义详情
     * @param request
     * @return
     */
    @Override
    public AjaxResult queryThingModelPublished(QueryThingModelPublishedRequest request) {
        //设置阿里云实例ID
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        //IOT中查询模型详细信息
        QueryThingModelPublishedResponse response;
        try {
            response=client.queryThingModelPublished(request);
        } catch (Exception e) {
            throw new BaseException("查询物模型失败");
        }
        //状态码
        if(!response.getBody().success){
            throw new BaseException("查询物模型失败");
        }
        return AjaxResult.success(response.getBody().getData());
    }

    /**
     * 查询指定设备的物模型运行状态
     *
     * @param request
     * @return
     */
    @Override
    public AjaxResult queryDevicePropertyStatus(QueryDevicePropertyStatusRequest request) {
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDevicePropertyStatusResponse response;
        try {
            response=client.queryDevicePropertyStatus(request);
        } catch (Exception e) {
            throw  new BaseException("");
        }
        if(!response.getBody().success){
            throw new BaseException(response.getBody().getErrorMessage());
        }
        return AjaxResult.success(response.getBody().getData());
    }

    /**
     * 删除设备
     *
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteDevice(DeleteDeviceRequest request) {
        deviceMapper.delete(Wrappers.<Device>lambdaQuery()
                .eq(Device::getIotId,request.getIotId())
                .eq(Device::getProductKey,request.getProductKey()));
        //删除IOT平台上的设备
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());

        DeleteDeviceResponse response;
        try {
            response=client.deleteDevice(request);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if(!response.getBody().success){
            throw new BaseException("IOT平台设备删除失败。");
        }
    }
}
